#include "shape.h"

#include<algorithm>
using std::min;
using std::max;

//! Creates the Bounding Volume structure of this Shape
/*! Returns a pair of points that represents the Bounding Volume
 */
pair<Point3D, Point3D> Shape::getBoundingVolume() {
	double side1 = height;
	side1 = max(side1, width);
	side1 = max(side1, depth);
	
	pair<Point3D, Point3D> bv1;
	bv1.first.x = position.x - side1/2.;
	bv1.first.y = position.y - side1/2.;
	bv1.first.z = position.z - side1/2.;
	bv1.second.x = position.x + side1/2.;
	bv1.second.y = position.y + side1/2.;
	bv1.second.z = position.z + side1/2.;
	
	return bv1;
}

//! Executes a rotation of the object in X direction
void Shape::rotX(double angle, double axisX, double axisY, double axisZ) {
	double y = position.y - axisY;
	double z = position.z - axisZ;
	rotateX = vec3( rotateX.x, rotateX.y*cos(angle)- rotateX.z*sin(angle) , rotateX.y*sin(angle) + rotateX.z*cos(angle) );
	rotateY = vec3( rotateY.x, rotateY.y*cos(angle)- rotateY.z*sin(angle) , rotateY.y*sin(angle) + rotateY.z*cos(angle) );
	rotateY = vec3( rotateZ.x, rotateZ.y*cos(angle)- rotateZ.z*sin(angle) , rotateZ.y*sin(angle) + rotateZ.z*cos(angle) );
	
	double newy = y*cos(angle) - z*sin(angle);
	double newz = y*sin(angle) + z*cos(angle);
	
	position.y += newy-y;
	position.z += newz-z;
	azimuthX += angle/DegreesToRadians;
}
	
//! Executes a rotation of the object in Y direction
void Shape::rotY(double angle, double axisX, double axisY, double axisZ) {
	double x = position.x - axisX;
	double z = position.z - axisZ;
	rotateX = vec3( rotateX.x*cos(angle) + rotateX.z*sin(angle), rotateX.y , -rotateX.x*sin(angle) + rotateX.z*cos(angle) );
	rotateY = vec3( rotateY.x*cos(angle) + rotateY.z*sin(angle), rotateY.y , -rotateY.x*sin(angle) + rotateY.z*cos(angle) );
	rotateZ = vec3( rotateZ.x*cos(angle) + rotateZ.z*sin(angle), rotateZ.y , -rotateZ.x*sin(angle) + rotateZ.z*cos(angle) );
	
	double newx = x*cos(angle) + z*sin(angle);
	double newz = -x*sin(angle) + z*cos(angle);
	
	position.x += newx-x;
	position.z += newz-z;
	azimuthY += angle/DegreesToRadians;
}
	
//! Executes a rotation of the object in Z direction
void Shape::rotZ(double angle, double axisX, double axisY, double axisZ) {
	double x = position.x - axisX;
	double y = position.y - axisY;
	rotateX = vec3( rotateX.x*cos(angle) - rotateX.y*sin(angle), rotateX.x*sin(angle) + rotateX.y*cos(angle) , rotateX.z );
	rotateY = vec3( rotateY.x*cos(angle) - rotateY.y*sin(angle), rotateY.x*sin(angle) + rotateY.y*cos(angle) , rotateY.z );
	rotateZ = vec3( rotateZ.x*cos(angle) - rotateZ.y*sin(angle), rotateZ.x*sin(angle) + rotateZ.y*cos(angle) , rotateZ.z );
	
	double newx = x*cos(angle) - y*sin(angle);
	double newy = x*sin(angle) + y*cos(angle);
	
	position.x += newx-x;
	position.y += newy-y;
	azimuthZ += angle/DegreesToRadians;
}

///----------------- GETTERS AND SETTERS -----------------

//! Returns the private field position
vec3 Shape::getPosition() {
	return position;
}

//! Returns the private field rotateX
vec3 Shape::getRotateX(){
	return rotateX;
}

//! Returns the private field rotateY
vec3 Shape::getRotateY(){
	return rotateY;
}

//! Returns the private field rotateZ
vec3 Shape::getRotateZ(){
	return rotateZ;
}

//! Returns the private field azimuthX
double Shape::getAzimuthX() {
	return azimuthX;
}

//! Returns the private field azimuthY
double Shape::getAzimuthY() {
	return azimuthY;
}

//! Returns the private field azimuthZ
double Shape::getAzimuthZ() {
	return azimuthZ;
}

//! Returns the private field height
double Shape::getHeight() {
	return height;
}

//! Returns the private field width
double Shape::getWidth() {
	return width;
}

//! Returns the private field depth
double Shape::getDepth() {
	return depth;
}

//! Changes the private field position
void Shape::setPosition(vec3 newPos) {
	this->position = newPos;
}

//! Changes the private field azimuth
void Shape::setAzimuthX(double azimuth){
	if (azimuth > 360.)
		this->azimuthX = azimuth - 360.;
	else if (azimuth < -360.)
		this->azimuthX = azimuth + 360.;
}

//! Changes the private field azimuth
void Shape::setAzimuthY(double azimuth){
	if (azimuth > 360.)
		this->azimuthY = azimuth - 360.;
	else if (azimuth < -360.)
		this->azimuthY = azimuth + 360.;
}

//! Changes the private field azimuth
void Shape::setAzimuthZ(double azimuth){
	if (azimuth > 360.)
		this->azimuthZ = azimuth - 360.;
	else if (azimuth < -360.)
		this->azimuthZ = azimuth + 360.;
}

//! Changes the private field height
void Shape::setHeight(double height){
	this->height = height;
}

//! Changes the private field width
void Shape::setWidth(double width){
	this->width = width;
}

//! Changes the private field depth
void Shape::setDepth(double depth){
	this->depth = depth;
}
